#include "app_ota.h"
#include "app.h"
#include "flash.h"
#include "bootloader.h"
#include "sensor_service.h"
#include "crc.h"
#include "tftp_server.h"
#include "stm32l0xx_nucleo.h"
#include "crc32.h"
#include "error.h"
#include "wdg.h"
/*private varible****************************************************************************************************/
extern volatile uint8_t system_state;
/*private fucntion***************************************************************************************************/
extern void FLASH_Program_Word(uint32_t Address, uint32_t Data);
bool _erase_cmd_open(char* name, uint8_t mode);


bool _erase_cmd_open(char* name, uint8_t mode)
{
    uint32_t page_error;
    uint32_t pre_crc = 0,after_crc = 0;
    FLASH_EraseInitTypeDef EraseInitStruct;
    
    if (mode != TFTP_WRQ) return false;
    
    if (0 == strcmp(name, "erase.cmd")) {
        HAL_FLASH_Unlock();
        /* Erase the user Flash area*/
        /* Fill EraseInit structure*/
        EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
        EraseInitStruct.PageAddress = OTA_ADDR;
        EraseInitStruct.NbPages = 32;
    
        pre_crc = crc32((uint8_t*)BOOT_ADDR, 4096);
        
        if (HAL_FLASHEx_Erase(&EraseInitStruct, &page_error) != ota_ok){
            app_fault_handle(APP_OTA_ERASE_ERROR);
            return false;
        }
        
        after_crc = crc32((uint8_t*)BOOT_ADDR, 4096);
        if(pre_crc != after_crc){
            app_fault_handle(APP_OTA_BOOOTLOADER_CRC_ERROR);
        }
		
        HAL_FLASH_Lock();
        return true;
    
    } else {
        return false;
    }
}

uint16_t (_erase_cmd_read)(uint8_t blk, uint8_t* buffer)
{
    return 0;
}

void (_erase_cmd_write)(uint8_t blk, uint8_t* buffer, uint16_t len)
{
}

void (_erase_cmd_close)(void)
{
//    HAL_FLASH_Lock();
}

const tftp_server_plugin_t tftp_server_plugin_erase_cmd = {
    _erase_cmd_open,
    _erase_cmd_read,
    _erase_cmd_write,
    _erase_cmd_close,
};

bool _ota_image_open(char* name, uint8_t mode)
{
    if (mode != TFTP_WRQ) return false;
    
    if (0 == strcmp(name, "ota.img")) {
        return true;
    } else {
        return false;
    }
}

uint16_t (_ota_image_read)(uint8_t blk, uint8_t* buffer)
{
    return 0;
}

void (_ota_image_write)(uint8_t blk, uint8_t* buffer, uint16_t len)
{
    int i;
    uint32_t addr;
    uint16_t count = len  / 4;
    uint32_t* p = (uint32_t*)buffer;
    uint32_t page_error;

    FLASH_EraseInitTypeDef EraseInitStruct;
    
    blk -= 1;
    addr = OTA_ADDR + blk * 512;
   
    HAL_FLASH_Unlock();
    /*clear  write proctect flag*/
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_WRPERR);
    if ((addr % (PAGE_SIZE * 32)) == 0) {
        
        EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
        EraseInitStruct.PageAddress = addr;
        EraseInitStruct.NbPages =32;
     
        if (HAL_FLASHEx_Erase(&EraseInitStruct, &page_error) != 0x00){
            app_fault_handle(APP_OTA_ERASE_ERROR);
            return;
        }
    }
	 
    for (i = 0; i < count; i++) {
        if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, p[i]) != 0x00){
            app_fault_handle(APP_OTA_PROGRAM_ERROR);
            return ;
        }
        addr += 4;
    }
	
    HAL_FLASH_Lock();
 
}
 
void (_ota_image_close)(void)
{
    system_state = TRUE;
}

const tftp_server_plugin_t tftp_server_plugin_ota_image = {
    _ota_image_open,
    _ota_image_read,
    _ota_image_write,
    _ota_image_close,
};

